#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include "Log.hpp"
Log logger;
enum
{
    Usage_Err=1,
    Socket_Err=2,
    Bind_Err,
    Listen_Err
};

const int defaultfd=-1;
std::string defaultip="0.0.0.0";
const int backlog=10;

class tcpServer;

class ThreadData
{
public:
    ThreadData(int fd,const std::string& ip,const uint16_t &port,tcpServer *t)
    :sockfd(fd)
    ,clientip(ip)
    ,clientport(port)
    ,tsvr(t)
    {}
public:
    int sockfd;       
    std::string clientip;      
    uint16_t clientport;
    tcpServer *tsvr;
};

//面向连接，字节流
class tcpServer
{
public:
    tcpServer(const uint16_t &port,const std::string& ip=defaultip)
    :_listensock(defaultfd)
    ,_ip(ip)
    ,_port(port)
    {}
    void Init()
    {
        //1.创建套接字
        _listensock=socket(AF_INET,SOCK_STREAM,0);
        if(_listensock<0)
        {
            logger(Fatal,"socket create error,sockfd:%d",_listensock);
            exit(Socket_Err);
        }
        logger(Info,"sockfd create success,sockfd:%d",_listensock);
        //2.绑定套接字
        struct sockaddr_in local;           
        memset(&local,0,sizeof(local));                
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=INADDR_ANY;             //也可如下写法
        //inet_aton(_ip.c_str(),&(local.sin_addr));       //字符串IP地址转换为一个32位的网络序列IP地址

        if(bind(_listensock,(struct sockaddr*)&local,sizeof(local))<0)
        {
            logger(Fatal,"bind error,errno: %d,errstring: %s",errno,strerror(errno));
            exit(Bind_Err);
        }
        logger(Info,"bind socket success,sockfd: %d",_listensock);

        if(listen(_listensock,backlog)<0)
        {
            logger(Fatal,"listen error,errno: %d,errstring: %s",errno,strerror(errno));
            exit(Listen_Err);
        }
        logger(Info,"listen socket success,sockfd: %d",_listensock);
    }

    //static方式无法使用类内非static成员方法
    static void *Routine(void*args)             //成员函数内部都有一个this指针，添加static
    {
        //pthread_detach()：将该线程设为分离状态。pthread_self()：获取当前线程的 ID。
        pthread_detach(pthread_self());

        //static_cast是 C++ 的类型转换运算符，用于在相关类型（如void*和ThreadData*）之间进行安全转换
        ThreadData *td=static_cast<ThreadData *>(args);     //形参void*转为ThreadData*

        td->tsvr->Service(td->sockfd,td->clientip,td->clientport);    //执行的服务（任务）
        delete td;
        return nullptr;
    }

    void Start()
    {
        signal(SIGCHLD,SIG_IGN);
        logger(Info,"tcpServer is running....");
        for(;;)
        {
            //获取新连接
            struct sockaddr_in client;
            socklen_t len=sizeof(client);
            int sockfd=accept(_listensock,(struct sockaddr*)&client,&len);
            if(sockfd<0)
            {
                logger(Warrning,"accept error,errno: %d,errstring: %s",errno,strerror(errno));
                continue;
            }           
            char clientip[32];
            uint16_t clientport=ntohs(client.sin_port);                     //获取客户端的端口号
            inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));   //获取客户ip并转为主机序列
            
            //根据新连接来进行通信,提供服务
            logger(Info,"get a new link...,sockfd: %d, client ip: %s, client port: %d\n",sockfd,clientip,clientport);

            
            //version 1,单进程
            //Service(sockfd,clientip,clientport);
            //close(sockfd);

            //version 2,多进程，父进程和孙子进程同时执行
            /*           
            pid_t id=fork();

            //子进程
            if(id==0)       
            {
                close(_listensock);             //关闭父进程文件描述符

                //子进程创建孙子进程后，子进程退出是为了被父进程早点等待成功而不阻塞，由孙子进程执行具体任务
                if(fork()>0) exit(0);
                Service(sockfd,clientip,clientport);    
                close(sockfd);
                exit(0);
            }

            //父进程
            close(sockfd);                      //关闭子进程的文件描述符
            pid_t rid=waitpid(id,nullptr,0);
            (void)rid;
            */

           //version 3,多线程,主线程获取新链接，新线程执行任务
            ThreadData *td=new ThreadData(sockfd,clientip,clientport,this);
            pthread_t pid;
            pthread_create(&pid,nullptr,Routine,td); 
        }
    }

   

    //读写数据
    void Service(int sockfd,const std::string &clientip,const uint16_t &clientport)
    {
        //测试返回数据
        char buf[4096];
        while(1)
        {
            ssize_t n=read(sockfd,buf,sizeof(buf));
            if(n>0)    
            {
                buf[n]=0;
                std::cout<<"client say# "<<buf<<std::endl;
                std::string echo_string="tcpserver echo# ";
                echo_string+=buf;
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
            else if(n==0)           //客户端退出
            {
                logger(Info,"%s:%d quit,server close sockfd: %d",clientip.c_str(),clientport,sockfd);
                break;
            }
            else
            {
                logger(Warrning,"read error,sockfd: %d,client ip: %d,client port: %d",sockfd,clientip.c_str(),clientport);
                break;
            }
        }
    }
    ~tcpServer()
    {}

private:
    int _listensock;        //网络文件描述符
    std::string _ip;        //任意地址bind 0
    uint16_t _port;         //服务器进程端口号
}; 